home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
oper_sys
/
presto
/
prest1_0.lha
/
src
/
locks.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-12-11
|
4KB
|
238 lines
/*
* locks.c
* Definitions some derived synchro classes
*
*/
#define _LOCKS_C
#include "presto.h"
#include "locks.h"
Lock::Lock(char *name) : SynchroObject (OBJ_LOCK, name)
{
lo_owner = 0;
}
Lock::Lock(char *name, int locktype) : SynchroObject (locktype, name)
{
lo_owner = 0;
}
Lock::~Lock()
{
if (lo_owner)
error("Can't delete a held lock!");
}
//
// Threads are given ownership of the lock on ENTRY iff there
// is no current owner. On EXIT, we just clear the owner field
// and wakeup the first guy on the queue.
// Inline version falls through to lock if the lock is already
// held. This optimizes entry for non-occupied routines.
//
void
Lock::lock()
{
SynchroObject::lock();
if (lo_owner == 0) {
lo_owner = thisthread;
SynchroObject::unlock();
} else
lock2();
}
void
Lock::unlock()
{
SynchroObject::lock();
if (thisthread != lo_owner)
error("Can't release someone else's lock");
lo_owner = 0;
Thread *newowner = recall(); // find new lock owner
//
// Dont guarantee fairness
//
SynchroObject::unlock();
if (newowner)
newowner->wakeup((SynchroObject*)this);
}
//
// Secondary looping entry point for a lock
//
void
Lock::lock2()
{
if (thisthread->flags()&TF_SCHEDULER)
error("Can't block a scheduler thread!");
// expect lock to be held on the way in
for (;;) {
if (lo_owner == 0)
break;
remember(thisthread);
SynchroObject::unlock();
thisthread->sleep(this);
SynchroObject::lock();
}
lo_owner = thisthread;
SynchroObject::unlock();
}
void
Lock::print(ostream& s)
{
s << "Lock:";
SynchroObject::print(s);
s << form(" lo_owner=0x%x", lo_owner);
}
Monitor::Monitor(char* name) : Lock (name, OBJ_MONITOR)
{
}
Monitor::~Monitor()
{
if (owner())
error("can't delete a held monitor");
}
void
Monitor::print(ostream& s)
{
s << "Monitor:";
Lock::print(s);
}
//
// Condition variables are bound to monitors. If you run a condition
// variable UNBOUND, and you do not guarantee that operations on the
// condition variable are atomic (locked), bad things will happen.
// Condition variables assume that they will only be referenced
// from within a monitor, so they don't bother to lock their data
// structures when referenced.
//
Condition::Condition(char *name) : SynchroObject (OBJ_CONDVAR, name)
{
cerr << "Warning: use of unbound condition variable " << name <<
" is not advised\n";
co_monitor = 0;
}
Condition::Condition(Monitor* boundmon) : SynchroObject (OBJ_CONDVAR,0)
{
co_monitor = boundmon;
}
Condition::Condition(Monitor &boundmon) : SynchroObject (OBJ_CONDVAR, 0)
{
co_monitor = &boundmon;
}
Condition::Condition(Monitor* boundmon, char* name) : SynchroObject (OBJ_CONDVAR,name)
{
co_monitor = boundmon;
}
Condition::Condition(Monitor& boundmon, char* name) : SynchroObject (OBJ_CONDVAR, name)
{
co_monitor = &boundmon;
}
Condition::~Condition()
{
}
//
// Signal a condition variable. Backlogs probably will not get
// implemented because they may have nasty overtones.
// No locking needed since we assume we are inside monitored region
//
void
Condition::broadcast()
{
Thread *t;
if (!threadok())
error("Condition broadcast by non-owning thread!");
while (t = waitingQueue()->get()) { // DO NOT LOCK
t->wakeup(this);
}
}
//
// No locking here either
//
void
Condition::signal()
{
if (!threadok())
error("Condition signal by non-owning thread!");
Thread *t = waitingQueue()->get(); // DO NOT LOCK
if (t)
t->wakeup(this);
}
//
// Put a thread to sleep on a condition variable.
// Get the monitor which we currently hold and exit it.
//
// We must be responsible for remembering threads which need to
// be reawoken on an event of this condition. If we relied on
// the sleep routines, it is possible that we could wakeup someone
// up, have them start running, and signal us, yet we have not been
// remembered since our sleep call hadn't yet gotten far enough.
//
// No locking here also
//
void
Condition::wait()
{
if (!threadok())
error("Condition wait by non-owning thread!");
remember(thisthread); // will NOT lock the queue
if (co_monitor) { // release the monitor
co_monitor->exit();
}
thisthread->sleep(this);
// reaquire the monitor if we gave it up
if (co_monitor) {
co_monitor->entry();
}
}
void
Condition::print(ostream& s)
{
s << "Condition:";
SynchroObject::print(s);
s << " bound ";
if (co_monitor)
s << co_monitor;
else
s << "_unbound_";
}